﻿#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Security;
using System.Windows;
#if !SL
using System.IO.Compression;
#endif
#if DEMODATA
using DevExpress.Internal;
#endif
#if DEMODATA
namespace UColor.Core.Utils {
#else
#if DEMO
namespace DevExpress.Internal {
#else
namespace DevExpress.Utils {
#endif
#endif
	public static class AssemblyHelper {
		static Dictionary<Assembly, string> defaultNamespaces = new Dictionary<Assembly, string>();
		const string PublicKeyTokenString = "PublicKeyToken";
#if !SL
		static Assembly entryAssembly;
		public static Assembly EntryAssembly { 
			get { return entryAssembly ?? (entryAssembly = Assembly.GetEntryAssembly()); }
			set { entryAssembly = value; }
		}
		const int PublicKeyTokenBytesLength = 8;
		static byte[] StringToBytes(string str) {
			int bytesLength = str.Length / 2;
			byte[] bytes = new byte[bytesLength];
			for(int i = 0; i < bytesLength; i++) {
				bytes[i] = byte.Parse(str.Substring(2 * i, 2), System.Globalization.NumberStyles.HexNumber);
			}
			return bytes;
		}
		public static string GetAssemblyFullName(string name, string version, System.Globalization.CultureInfo culture, string publicKeyToken) {
			AssemblyName asmName = new AssemblyName();
			asmName.Name = name;
			asmName.Version = new Version(version);
			asmName.CultureInfo = culture;
			if(publicKeyToken != null && publicKeyToken.Length == 2 * PublicKeyTokenBytesLength) {
				asmName.SetPublicKeyToken(StringToBytes(publicKeyToken));
			}
			return asmName.FullName;
		}
		public static Assembly GetThemeAssembly(string themeName) {
			string assemblyName = GetThemeAssemblyName(themeName);
			Assembly assembly = AssemblyHelper.GetLoadedAssembly(assemblyName);
			if(assembly != null)
				return assembly;
			return LoadDXAssembly(assemblyName);
		}
		public static string GetShortNameWithoutVersion(Assembly assembly) {
			return GetShortNameWithoutVersion(assembly.FullName);
		}
		public static string GetShortNameWithoutVersion(string fullName) {
			string name = fullName.Split(',')[0];
			string nameWithoutVSuffix = name.Replace(AssemblyInfo.VSuffix, string.Empty);
			return nameWithoutVSuffix;
		}
		static Assembly GetReflectionOnlyLoadedAssembly(string asmName) {
			try {
				return Assembly.ReflectionOnlyLoad(asmName);
			} catch {
				return null;
			}
		}
		public static bool HasAttribute(string assemblyName, Type attributeType) {
			return HasAttribute(GetLoadedAssembly(assemblyName), attributeType);
		}
		public static bool HasAttribute(Assembly assembly, Type attributeType) {
			if(assembly != null) {
				return Attribute.IsDefined(assembly, attributeType);
			}
			return false;
		}
#endif
		public static bool IsLoadedAssembly(string assemblyName) {
			return GetLoadedAssembly(assemblyName) != null;
		}
		public static Assembly GetLoadedAssembly(string asmName) {
			IEnumerable assemblies = GetLoadedAssemblies();
			foreach (Assembly asm in assemblies) {
				if (PartialNameEquals(asm.FullName, asmName))
					return asm;
			}
			return null;
		}
		public static IEnumerable<Assembly> GetLoadedAssemblies() {
			return AppDomain.CurrentDomain.GetAssemblies();
		}
		public static string GetThemeAssemblyFullName(string themeName) {
			return GetThemeAssemblyName(themeName) + GetFullNameAppendix();
		}
		public static string GetThemeAssemblyName(string themeName) {
			return AssemblyInfo.SRAssemblyXpfPrefix + AssemblyInfo.ThemePrefix + themeName + AssemblyInfo.VSuffix;
		}
		public static Assembly LoadDXAssembly(string assemblyName) {
			Assembly assembly = null;
			try {
				assembly = Assembly.Load(assemblyName + GetFullNameAppendix());
			} catch {
			}
			return assembly;
		}
		static string GetFullNameAppendix() {
			return ", Version=" + AssemblyInfo.Version + ", Culture=neutral, " + PublicKeyTokenString + "=" + GetCoreAssemblyPublicKeyToken();
		}
		public static string GetCoreAssemblyPublicKeyToken() {
			string coreAssemblyName = GetDXAssemblyFullName();
			int publicKeyTokenIndex = coreAssemblyName.IndexOf(PublicKeyTokenString, StringComparison.Ordinal);
			int publicKeyTokenLenght = "31bf3856ad364e35".Length;
			return typeof(AssemblyHelper).Assembly.FullName.Substring(publicKeyTokenIndex + (PublicKeyTokenString + "=").Length, publicKeyTokenLenght);
		}
		static string GetDXAssemblyFullName() {
			Assembly assemblyHelperAssembly = typeof(AssemblyHelper).Assembly;
			string assemblyFullName = assemblyHelperAssembly.FullName;
			if(NameContains(Assembly.GetExecutingAssembly().FullName, AssemblyInfo.SRAssemblyData)) return assemblyFullName;
			if(NameContains(Assembly.GetExecutingAssembly().FullName, AssemblyInfo.SRAssemblyDemoDataCore)) return assemblyFullName;
			throw new NotSupportedException(string.Format("Wrong DX assembly: {0}", assemblyFullName));
		}
		public static Assembly GetAssembly(string assemblyFullName) {
			Assembly assembly = AssemblyHelper.GetLoadedAssembly(assemblyFullName);
			if(assembly != null) return assembly;
			return Assembly.Load(assemblyFullName);
		}
		public static bool NameContains(string assemblyFullName, string assemblyName) {
			return AssertAssemblyName(assemblyFullName, assemblyName);
		}
		public static bool NameContains(Assembly assembly, string assemblyName) {
			return AssertAssemblyName(assembly.FullName, assemblyName);
		}
		public static bool NameContains(AssemblyName assembly, string assemblyName) {
			return AssertAssemblyName(assembly.FullName, assemblyName);
		}
		public static bool IsDXProductAssembly(Assembly assembly) {
			return NameContains(assembly, AssemblyInfo.SRAssemblyXpfPrefix) && !IsDXThemeAssembly(assembly);
		}
		public static bool IsDXProductAssembly(string assemblyFullName) {
			return NameContains(assemblyFullName, AssemblyInfo.SRAssemblyXpfPrefix) && !IsDXThemeAssembly(assemblyFullName);
		}
		public static bool IsDXThemeAssembly(Assembly assembly) {
			return NameContains(assembly, AssemblyInfo.ThemePrefixWithoutSeparator);
		}
		public static bool IsDXThemeAssembly(string assemblyName) {
			return NameContains(assemblyName, AssemblyInfo.ThemePrefixWithoutSeparator);
		}
		public static bool IsEntryAssembly(Assembly assembly) {
#if SL
			string entryAssemblyName = Deployment.Current.EntryPointAssembly;
			return NameContains(assembly, entryAssemblyName);
#else
			Assembly entryAssembly = EntryAssembly;
			return entryAssembly == assembly;
#endif
		}
		public static bool IsEntryAssembly(string assemblyName) {
#if SL
			string entryAssembly = Deployment.Current.EntryPointAssembly;
#else
			Assembly entryAssembly = EntryAssembly;
#endif
			if(entryAssembly == null)
				return false;
			return NameContains(entryAssembly, assemblyName);
		}
		static bool AssertAssemblyName(string fullName, string assemblyName) {
			if(string.IsNullOrEmpty(assemblyName))
				return false;
			return fullName.ToLowerInvariant().Contains(assemblyName.ToLowerInvariant());
		}
		public static string CombineUri(params string[] parts) {
			if(parts.Length == 0) return string.Empty;
			string ret = parts[0];
			for(int i = 1; i < parts.Length; ++i) {
				ret += "/" + parts[i];
			}
			ret = ret.Replace('\\', '/');
			while(ret.Contains("//"))
				ret = ret.Replace("//", "/");
			if(ret.Length > 1 && ret[ret.Length - 1] == '/') ret = ret.Remove(ret.Length - 1);
			if((parts[0].Length == 0 || parts[0][0] != '/') && ret.Length != 0 && ret[0] == '/') ret = ret.Substring(1);
			return ret;
		}
		public static bool PartialNameEquals(string asmName0, string asmName1) {
			return string.Equals(GetPartialName(asmName0), GetPartialName(asmName1), StringComparison.InvariantCultureIgnoreCase);
		}
		public static string GetPartialName(string asmName) {
			AssemblyName name = new AssemblyName(asmName);
			string str = name.Name;
			return str == null ? string.Empty : str;
		}
		public static string GetPartialName(Assembly assembly) {
			return GetPartialName(assembly.FullName);
		}
		public static IDictionaryEnumerator GetResourcesEnumerator(Assembly assembly) {
			string baseName = GetPartialName(assembly) + ".g";
			ResourceManager resourceManager = new ResourceManager(baseName, assembly);
			ResourceSet rs = resourceManager.GetResourceSet(System.Globalization.CultureInfo.InvariantCulture, true, false);
			return rs == null ? null : rs.GetEnumerator();
		}
		public static Uri GetResourceUri(Assembly assembly, string path) {
#if SL
			return new Uri(string.Format("/{0};component/{1}", GetPartialName(assembly), path), UriKind.Relative);
#else
			return new Uri(string.Format("{0}/{1};component/{2}", "pack://application:,,,", AssemblyHelper.GetPartialName(assembly), path));
#endif
		}
		public static Stream GetResourceStream(Assembly assembly, string path, bool pathIsFull) {
			path = path.ToLowerInvariant();
			Stream stream = GetResourceStreamCore(assembly, path, pathIsFull);
#if SL
			return stream;
#else
			if(stream == null) {
				stream = GetResourceStreamCore(assembly, path + ".zip", pathIsFull);
				if(stream != null)
					stream = new GZipStream(stream, CompressionMode.Decompress);
			}
			return stream;
#endif
		}
		public static Stream GetEmbeddedResourceStream(Assembly assembly, string name, bool nameIsFull) {
			name = name.Replace('/', '.');
			Stream stream = GetEmbeddedResourceStreamCore(assembly, name, nameIsFull);
#if SL
			return stream;
#else
			if(stream == null) {
				stream = GetEmbeddedResourceStreamCore(assembly, name + ".zip", nameIsFull);
				if(stream != null)
					stream = new GZipStream(stream, CompressionMode.Decompress);
			}
			return stream;
#endif
		}
		public static string GetNamespace(Type type) {
			string typeName = type.FullName;
			int d = typeName.LastIndexOf('.');
			return d < 0 ? string.Empty : typeName.Remove(d);
		}
		public static string GetDefultNamespace(Assembly assembly) {
			string defaultNamespace;
			if(!defaultNamespaces.TryGetValue(assembly, out defaultNamespace)) {
				defaultNamespace = GetDefultNamespaceCore(assembly);
				defaultNamespaces.Add(assembly, defaultNamespace);
			}
			return defaultNamespace;
		}
		public static string GetCommonPart(string[] strings, string[] excludedSuffixes) {
			string commonPart = null;
			foreach(string s in strings) {
				bool hasExcludedSuffix = false;
				foreach(string excludedSuffix in excludedSuffixes) {
					if(s.EndsWith(excludedSuffix, StringComparison.Ordinal)) {
						hasExcludedSuffix = true;
						break;
					}
				}
				if(hasExcludedSuffix) continue;
				if(commonPart == null) {
					commonPart = s;
					continue;
				}
				if(s.IndexOf(commonPart, StringComparison.Ordinal) != 0) {
					int differ = 0;
					for(int d = 0; d < commonPart.Length & d < s.Length; ++d) {
						if(d >= commonPart.Length || d >= s.Length || commonPart[d] != s[d]) {
							differ = d;
							break;
						}
					}
					commonPart = commonPart.Remove(differ);
				}
			}
			return commonPart == null ? string.Empty : commonPart;
		}
		static Stream GetResourceStreamCore(Assembly assembly, string path, bool pathIsFull) {
			IDictionaryEnumerator enumerator = GetResourcesEnumerator(assembly);
			if(enumerator == null) return null;
			while(enumerator.MoveNext()) {
				string resourceName = (string)enumerator.Key;
				if(resourceName == path || !pathIsFull && resourceName.EndsWith("/" + path, StringComparison.Ordinal))
					return enumerator.Value as Stream;
			}
			return null;
		}
		static Stream GetEmbeddedResourceStreamCore(Assembly assembly, string name, bool nameIsFull) {
			string fullName = GetDefultNamespace(assembly) + name;
			Stream stream = assembly.GetManifestResourceStream(fullName);
			if(stream != null || nameIsFull) return stream;
			foreach(string resourceName in assembly.GetManifestResourceNames()) {
				if(resourceName.EndsWith("." + name, StringComparison.Ordinal))
					return assembly.GetManifestResourceStream(resourceName);
			}
			return null;
		}
		static string GetDefultNamespaceCore(Assembly assembly) {
			try {
				object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyDefaultNamespaceAttribute), true);
				if(attributes.Length != 0) return ((AssemblyDefaultNamespaceAttribute)attributes[0]).DefaultNamespace + ".";
			} catch { }
			string[] names = assembly.GetManifestResourceNames();
			if(names.Length == 0) return string.Empty;
			return GetCommonPart(names.Length > 1 ? names : new string[] { names[0], GetPartialName(assembly) }, new string[] { ".csdl", ".ssdl", ".msl" });
		}
	}
	public class AssemblyDefaultNamespaceAttribute : Attribute {
		string defaultNamespace;
		public AssemblyDefaultNamespaceAttribute(string defaultNamespace) {
			this.defaultNamespace = defaultNamespace;
		}
		public string DefaultNamespace { get { return defaultNamespace; } }
	}
}
